Release 10.1A: OpenEdge Development:
Messaging and ESB


Application files

The sample application manages a set of customer records loaded from the sports.customer table. For each country, there is one instance of the application that manages the subset of customers from that country. The country is specified as an application startup parameter.

The gateway sample application consists of these three files:

The main loop of the application is in appDriver.p:

  1. The user specifies the Customer.Cust–num value.
  2. The application finds the customer and allows the user to update the record if the Customer.Country field matches the startup country.
  3. If the Customer.Country field does not match the startup country, the user can only view the customer record.
  4. Several applications, each managing one country, run concurrently. Each application is connected to a JMS server through a local JMS gateway object. The goal is to keep the records identical across the different locations.

  5. When an application modifies a customer record, it publishes the new record through a 4GL PUBLISH CustUpdate call.
  6. The local JMS gateway object subscribes to the CustUpdate event. It packs the published parameters in a JMS MapMessage and publishes it to the JMS CustUpdate topic.
  7. The other JMS gateway objects subscribe to the JMS CustUpdate topic. They receive the JMS MapMessage, unpack the parameters, and publish the updated record locally through a 4GL PUBLISH CustUpdate call.
  8. The application picks up the updated record and updates the local copy.

The procedure appDriver.p drives the publish and subscribe gateway example, as shown:

appDriver.p
/* appDriver.p: Drives the Pub/Sub gateway example. */ 
DEFINE INPUT PARAM country AS CHAR. 
DEFINE VAR customersH AS HANDLE. 
DEFINE VAR gatewayH AS HANDLE. 
DEFINE VAR custNum AS int. 
/* Initialization */ 
RUN customers.p PERSISTENT SET customersH. 
RUN loadCustomers IN customersH. 
RUN JMSgateway.p PERSISTENT SET gatewayH ("-H localhost -S 5162 "). 
/* Main loop. */ 
REPEAT: 
 custNum = ?. 
 UPDATE custNum label "cust-num" WITH FRAME ff CENTERED TITLE "Find Customer". 
 RUN updateCustInteractive IN customersH (custNum, country). 
END. 
RUN deleteGateway IN gatewayH. 

The procedure JMSgateway.p (1 of 2) establishes a gateway between local and remote publish and subscribe events, as shown:

JMSgateway.p
/* JMSgateway.p: A gateway between local and remote Pub/Sub events. */ 
DEFINE INPUT PARAM connectionParams AS CHAR. 
/* JMS objects */ 
DEFINE VARIABLE pubsubsession AS HANDLE. 
DEFINE VARIABLE outMessage AS HANDLE. 
DEFINE VARIABLE consumer AS HANDLE. 
/* Raw Transfer Declarations */ 
DEFINE TEMP-TABLE rawtt FIELD val AS RAW. 
CREATE rawtt. 
FUNCTION bufferToRaw RETURNS RAW (bufferH AS HANDLE) FORWARD. 
/* Initializes the JMS server and subscribes to the CustUpdate topic */ 
RUN jms/pubsubsession.p PERSISTENT SET pubsubsession (connectionParams). 
RUN setBrokerURL IN pubsubsession ("localhost:2506"). 
RUN beginSession IN pubsubsession. 
RUN createMapMessage IN pubsubsession (OUTPUT outMessage). 
RUN createMessageConsumer IN pubsubsession (THIS-PROCEDURE, 
                                "handleRemoteEvent", 
                                OUTPUT consumer). 
RUN subscribe IN pubsubsession (
            "CustUpdate", /* Topic name */ 
            ?,            /* Not durable. */ 
            ?,            /* No message selector */ 
            true,         /* No local events please */ 
            consumer). 
RUN startReceiveMessages IN pubsubsession. 
/* Subscribes to local CustUpdate events */ 
SUBSCRIBE TO "CustUpdate" ANYWHERE RUN-PROCEDURE "handleLocalEvent". 
/* Publish locally a remote message from the CustUpdate topic. */ 
PROCEDURE handleRemoteEvent: 
DEFINE INPUT PARAMETER messageH AS HANDLE NO-UNDO. 
DEFINE INPUT PARAMETER messageConsumerH AS HANDLE NO-UNDO. 
DEFINE OUTPUT PARAMETER replyH AS HANDLE NO-UNDO. 
  PUBLISH "CustUpdate" 
          (DATE (DYNAMIC-FUNCTION('getChar':U IN messageH, "updateDate")), 
          DYNAMIC-FUNCTION('getInt':U IN messageH, "custNum"), 
          DYNAMIC-FUNCTION('getBytesToRaw':U IN messageH, "rawCust")). 
  RUN deleteMessage IN messageH. 
END. 
/* Publish remotely a local CustUpdate event. */ 
PROCEDURE handleLocalEvent: 
DEFINE INPUT PARAMETER dt AS DATE. 
DEFINE INPUT PARAMETER custNum AS INT. 
DEFINE INPUT PARAMETER custBuffer AS HANDLE. 
    RUN setString IN outMessage ("updateDate", STRING(dt)). 
    RUN setInt IN outMessage ("custNum", custNum). 
    RUN setBytesFromRaw IN outMessage ("rawCust", bufferToRaw(custBuffer)). 
    RUN publish IN pubsubsession ("CustUpdate", outMessage,  ?,  ?,  ?). 
END. 
PROCEDURE deleteGateway: 
    RUN deleteMessage IN outMessage. 
    RUN deleteSession IN pubsubsession. 
    DELETE OBJECT THIS-PROCEDURE. 
END. 
FUNCTION bufferToRaw RETURNS RAW (bufferH AS HANDLE): 
    /* Raw Transfer Variables */ 
    DEFINE VAR rawbuf AS HANDLE. 
    DEFINE VAR rawCust AS HANDLE. 
    rawbuf = BUFFER rawtt:HANDLE. 
    rawCust = rawbuf:buffer-field(1). 
    bufferH:raw-transfer(true, rawCust). 
    RETURN rawCust:BUFFER-VALUE. 
END. 

The procedure customers.p updates customer records from a specified country while keeping the other records identical to the master copy, as shown:

customers.p 
/* customers.p: Manages customer records of a specified country and keeps the 
   other records identical to the master copy. */ 
DEFINE TEMP-TABLE custt LIKE customer. 
DEFINE BUFFER custtUpd FOR custt. 
DEFINE VAR custtH AS HANDLE. 
DEFINE VAR bufferH AS HANDLE. 
/* Getting a handle to a dynamic buffer. */ 
custtH = TEMP-TABLE custt:HANDLE. 
bufferH = custtH:DEFAULT-BUFFER-HANDLE. 
/* Subscribes to CustUpdate events. */ 
SUBSCRIBE TO "CustUpdate" ANYWHERE RUN-PROCEDURE "updateCustFromRaw". 
PROCEDURE loadCustomers: 
  FOR EACH customer: 
      CREATE custt. 
      buffer-copy customer to custt. 
  END. 
END. 
/* Updates a customer from the "correct" country, displays customers from 
   other countries. */ 
PROCEDURE updateCustInteractive. 
  DEFINE INPUT PARAM custNum AS INT. 
  DEFINE INPUT PARAM custCountry AS CHAR. 
  FIND custt WHERE custt.cust-num = custNum. 
  IF custt.country = custCountry THEN 
    DO: 
      UPDATE custt WITH 2 COL. 
      PUBLISH "CustUpdate" (TODAY, custNum, bufferH).  
    END. 
  ELSE 
    DISPLAY custt WITH 2 COL. 
END. 
/* Updates a customer record from a RAW value. */ 
PROCEDURE updateCustFromRaw: 
  DEFINE INPUT PARAM dt AS DATE. 
  DEFINE INPUT PARAM custNum AS INT. 
  DEFINE INPUT PARAM rawCust AS RAW. 
  FIND custtUpd WHERE custtUpd.cust-num = custNum. 
  RAW-TRANSFER rawCust TO custtUpd. 
  MESSAGE custNum VIEW-AS ALERT-BOX TITLE "customer updated". 
END. 


Copyright © 2005 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095